home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xskewb / Skewb.c < prev    next >
C/C++ Source or Header  |  1996-04-03  |  30KB  |  1,066 lines

  1. /*
  2. # X-BASED SKEWB
  3. #
  4. #  Skewb.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Skewb */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #ifdef VMS
  31. #include <unixlib.h>
  32. #else
  33. #ifndef apollo
  34. #include <unistd.h>
  35. #endif
  36. #endif
  37. #include <X11/IntrinsicP.h>
  38. #include <X11/Intrinsic.h>
  39. #include <X11/StringDefs.h>
  40. #include <X11/CoreP.h>
  41. #include "SkewbP.h"
  42. #include "Skewb2dP.h"
  43. #include "Skewb3dP.h"
  44.  
  45. #ifndef DATAFILE
  46. #define DATAFILE "/usr/games/lib/skewb.data"
  47. #endif
  48.  
  49. static void InitializeSkewb();
  50. static void DestroySkewb();
  51. static Boolean SetValuesSkewb();
  52. static void GetColor();
  53. static void MoveControlCb();
  54. static void MoveAltCb();
  55. static void ResetPolyhedrons();
  56. static int SelectPolyhedrons();
  57. static int NarrowSelection();
  58. static int PositionPolyhedrons();
  59. static void MoveNoPolyhedrons();
  60. static void PracticePolyhedrons();
  61. static void RandomizePolyhedrons();
  62. static void MovePolyhedrons();
  63. static void ReadDiagonal();
  64. static void RotateDiagonal();
  65. static void WriteDiagonal();
  66. static void ReadFace();
  67. static void WriteFace();
  68. static void RotateFace();
  69. static void DrawDiamond();
  70. static void DrawTriangle();
  71. static int CheckMoveDir();
  72.  
  73. SkewbClassRec skewbClassRec =
  74. {
  75.   {
  76.     (WidgetClass) &widgetClassRec,    /* superclass */
  77.     "Skewb",                /* class name */
  78.     sizeof(SkewbRec),            /* widget size */
  79.     NULL,                /* class initialize */
  80.     NULL,                /* class part initialize */
  81.     FALSE,                /* class inited */
  82.     InitializeSkewb,            /* initialize */
  83.     NULL,                /* initialize hook */
  84.     XtInheritRealize,            /* realize */
  85.     NULL,                /* actions */
  86.     0,                    /* num actions */
  87.     NULL,                /* resources */
  88.     0,                    /* num resources */
  89.     NULLQUARK,                /* xrm class */
  90.     TRUE,                /* compress motion */
  91.     TRUE,                /* compress exposure */
  92.     TRUE,                /* compress enterleave */
  93.     TRUE,                /* visible interest */
  94.     DestroySkewb,            /* destroy */
  95.     NULL,                /* resize */
  96.     NULL,                /* expose */
  97.     SetValuesSkewb,            /* set values */
  98.     NULL,                /* set values hook */
  99.     XtInheritSetValuesAlmost,        /* set values almost */
  100.     NULL,                /* get values hook */
  101.     NULL,                /* accept focus */
  102.     XtVersion,                /* version */
  103.     NULL,                /* callback private */
  104.     NULL,                /* tm table */
  105.     NULL,                /* query geometry */
  106.     NULL,                /* display accelerator */
  107.     NULL                /* extension */
  108.   },
  109.   {
  110.     0                    /* ignore */
  111.   }
  112. };
  113.  
  114. WidgetClass skewbWidgetClass = (WidgetClass) &skewbClassRec;
  115.  
  116. static SkewbLoc slideNextRow[MAXFACES][MAXORIENT][MAXORIENT / 2] =
  117. {
  118.   {
  119.     {{2,   CW}, {1, HALF}},
  120.     {{5,  CCW}, {1, STRT}},
  121.     {{3, STRT}, {5,   CW}},
  122.     {{3, HALF}, {2,  CCW}}
  123.   },
  124.   {
  125.     {{4, STRT}, {5,   CW}},
  126.     {{0, STRT}, {5,  CCW}},
  127.     {{2,  CCW}, {0, HALF}},
  128.     {{2,   CW}, {4, HALF}}
  129.   },
  130.   {
  131.     {{4,   CW}, {1,  CCW}},
  132.     {{0,  CCW}, {1,   CW}},
  133.     {{3,  CCW}, {0,   CW}},
  134.     {{3,   CW}, {4,  CCW}}
  135.   },
  136.   {
  137.     {{4, HALF}, {2,  CCW}},
  138.     {{0, HALF}, {2,   CW}},
  139.     {{5,   CW}, {0, STRT}},
  140.     {{5,  CCW}, {4, STRT}}
  141.   },
  142.   {
  143.     {{5,   CW}, {1, STRT}},
  144.     {{2,  CCW}, {1, HALF}},
  145.     {{3, HALF}, {2,   CW}},
  146.     {{3, STRT}, {5,  CCW}}
  147.   },
  148.   {
  149.     {{0,   CW}, {1,   CW}},
  150.     {{4,  CCW}, {1,  CCW}},
  151.     {{3,   CW}, {4,   CW}},
  152.     {{3,  CCW}, {0,  CCW}}
  153.   }
  154. };
  155. static SkewbLoc minToMaj[MAXFACES][MAXORIENT] =
  156. { /* other equivalent mappings possible */
  157.   {{3,   CW}, {2, STRT}, {1,  CCW}, {5, STRT}},
  158.   {{2, STRT}, {4,  CCW}, {5, HALF}, {0,   CW}},
  159.   {{3, STRT}, {4, STRT}, {1, STRT}, {0, STRT}},
  160.   {{5, HALF}, {4,   CW}, {2, STRT}, {0,  CCW}},
  161.   {{3,  CCW}, {5, STRT}, {1,   CW}, {2, STRT}},
  162.   {{3, HALF}, {0, STRT}, {1, HALF}, {4, STRT}}
  163. };
  164.  
  165. static SkewbLoc slideNextFace[MAXFACES][MAXORIENT] =
  166. {
  167.   {{5, STRT}, {3,   CW}, {2, STRT}, {1,  CCW}},
  168.   {{0,   CW}, {2, STRT}, {4,  CCW}, {5, HALF}},
  169.   {{0, STRT}, {3, STRT}, {4, STRT}, {1, STRT}},
  170.   {{0,  CCW}, {5, HALF}, {4,   CW}, {2, STRT}},
  171.   {{2, STRT}, {3,  CCW}, {5, STRT}, {1,   CW}},
  172.   {{4, STRT}, {3, HALF}, {0, STRT}, {1, HALF}}
  173. };
  174.  
  175. static int faceToRotate[MAXFACES][MAXORIENT] =
  176. {
  177.   {3, 2, 1, 5},
  178.   {2, 4, 5, 0},
  179.   {3, 4, 1, 0},
  180.   {5, 4, 2, 0},
  181.   {3, 5, 1, 2},
  182.   {3, 0, 1, 4}
  183. };
  184.  
  185. static SkewbLocPos orthToDiag[MAXFACES][MAXORIENT][MAXORIENT] =
  186. {
  187.   {
  188.     {{3, 0, 1}, {5, 1, 0}, {3, 0, 3}, {5, 1, 2}},
  189.     {{3, 3, 0}, {2, 0, 1}, {3, 3, 2}, {2, 0, 3}},
  190.     {{1, 0, 3}, {2, 3, 0}, {1, 0, 1}, {2, 3, 2}},
  191.     {{1, 3, 2}, {5, 2, 1}, {1, 3, 0}, {5, 2, 3}}
  192.   },
  193.   {
  194.     {{2, 3, 0}, {0, 2, 1}, {2, 3, 2}, {0, 2, 3}},
  195.     {{2, 2, 3}, {4, 3, 0}, {2, 2, 1}, {4, 3, 2}},
  196.     {{5, 3, 2}, {4, 2, 3}, {5, 3, 0}, {4, 2, 1}},
  197.     {{5, 2, 1}, {0, 3, 2}, {5, 2, 3}, {0, 3, 0}}
  198.   },
  199.   {
  200.     {{3, 3, 0}, {0, 1, 0}, {3, 3, 2}, {0, 1, 2}},
  201.     {{3, 2, 3}, {4, 0, 1}, {3, 2, 1}, {4, 0, 3}},
  202.     {{1, 1, 0}, {4, 3, 0}, {1, 1, 2}, {4, 3, 2}},
  203.     {{1, 0, 3}, {0, 2, 1}, {1, 0, 1}, {0, 2, 3}}
  204.   },
  205.   {
  206.     {{5, 1, 2}, {0, 0, 3}, {5, 1, 0}, {0, 0, 1}},
  207.     {{5, 0, 1}, {4, 1, 2}, {5, 0, 3}, {4, 1, 0}},
  208.     {{2, 1, 0}, {4, 0, 1}, {2, 1, 2}, {4, 0, 3}},
  209.     {{2, 0, 3}, {0, 1, 0}, {2, 0, 1}, {0, 1, 2}}
  210.   },
  211.   {
  212.     {{3, 2, 3}, {2, 1, 0}, {3, 2, 1}, {2, 1, 2}},
  213.     {{3, 1, 2}, {5, 0, 1}, {3, 1, 0}, {5, 0, 3}},
  214.     {{1, 2, 1}, {5, 3, 0}, {1, 2, 3}, {5, 3, 2}},
  215.     {{1, 1, 0}, {2, 2, 1}, {1, 1, 2}, {2, 2, 3}}
  216.   },
  217.   {
  218.     {{3, 1, 2}, {4, 1, 0}, {3, 1, 0}, {4, 1, 2}},
  219.     {{3, 0, 1}, {0, 0, 1}, {3, 0, 3}, {0, 0, 3}},
  220.     {{1, 3, 2}, {0, 3, 0}, {1, 3, 0}, {0, 3, 2}},
  221.     {{1, 2, 1}, {4, 2, 1}, {1, 2, 3}, {4, 2, 3}}
  222.   }
  223. };
  224.  
  225. static void InitializeSkewb(request, new)
  226.   Widget request, new;
  227. {
  228.   SkewbWidget w = (SkewbWidget) new;
  229.   XGCValues values;
  230.   XtGCMask valueMask;
  231.   int face;
  232.  
  233.   InitMoves();
  234.   ResetPolyhedrons(w);
  235.   (void) SRAND(getpid());
  236.   valueMask = GCForeground | GCBackground;
  237.   values.background = w->core.background_pixel;
  238.   values.foreground = w->skewb.foreground;
  239.   w->skewb.puzzleGC = XtGetGC(new, valueMask, &values);
  240.   values.foreground = w->skewb.borderColor;
  241.   w->skewb.borderGC = XtGetGC(new, valueMask, &values);
  242.   w->skewb.depth = DefaultDepthOfScreen(XtScreen(w));
  243.   valueMask = GCForeground | GCBackground;
  244.   values.foreground = w->core.background_pixel;
  245.   values.background = w->skewb.foreground;
  246.   w->skewb.inverseGC = XtGetGC(new, valueMask, &values);
  247.   for (face = 0; face < MAXFACES; face++)
  248.     GetColor(w, face, TRUE);
  249. }
  250.  
  251. static void DestroySkewb(old)
  252.   Widget old;
  253. {
  254.   SkewbWidget w = (SkewbWidget) old;
  255.   int face;
  256.  
  257.   for (face = 0; face < MAXFACES; face++)
  258.     XtReleaseGC(old, w->skewb.faceGC[face]);
  259.   XtReleaseGC(old, w->skewb.borderGC);
  260.   XtReleaseGC(old, w->skewb.puzzleGC);
  261.   XtReleaseGC(old, w->skewb.inverseGC);
  262.   XtRemoveCallbacks(old, XtNselectCallback, w->skewb.select);
  263. }
  264.  
  265. static Boolean SetValuesSkewb(current, request, new)
  266.   Widget current, request, new;
  267. {
  268.   SkewbWidget c = (SkewbWidget) current, w = (SkewbWidget) new;
  269.   XGCValues values;
  270.   XtGCMask valueMask;
  271.   Boolean redraw = FALSE;
  272.   int face;
  273.  
  274.   if (w->skewb.foreground != c->skewb.foreground) {
  275.     valueMask = GCForeground | GCBackground;
  276.     values.foreground = w->skewb.foreground;
  277.     values.background = w->core.background_pixel;
  278.     XtReleaseGC(new, w->skewb.puzzleGC);
  279.     w->skewb.puzzleGC = XtGetGC(new, valueMask, &values);
  280.     redraw = TRUE;
  281.   }
  282.   if (w->core.background_pixel != c->core.background_pixel) {
  283.     valueMask = GCForeground | GCBackground;
  284.     values.foreground = w->core.background_pixel;
  285.     values.background = w->skewb.foreground;
  286.     XtReleaseGC(new, w->skewb.inverseGC);
  287.     w->skewb.inverseGC = XtGetGC(new, valueMask, &values);
  288.     redraw = TRUE;
  289.   }
  290.   if (w->skewb.borderColor != c->skewb.borderColor) {
  291.     valueMask = GCForeground | GCBackground;
  292.     values.foreground = w->skewb.borderColor;
  293.     values.background = w->core.background_pixel;
  294.     XtReleaseGC(new, w->skewb.borderGC);
  295.     w->skewb.borderGC = XtGetGC(new, valueMask, &values);
  296.     redraw = TRUE;
  297.   }
  298.   if (w->skewb.mono || w->skewb.depth == 1) {
  299.     valueMask = GCForeground | GCBackground;
  300.     values.background = w->core.background_pixel;
  301.     values.foreground = w->skewb.foreground;
  302.     for (face = 0; face < MAXFACES; face++) {
  303.       XtReleaseGC(new, w->skewb.faceGC[face]);
  304.       w->skewb.faceGC[face] = XtGetGC(new, valueMask, &values);
  305.     }
  306.     redraw = TRUE;
  307.   }
  308.   for (face = 0; face < MAXFACES; face++) {
  309.     if (strcmp(w->skewb.faceName[face], c->skewb.faceName[face]))
  310.       GetColor(w, face, FALSE);
  311.   }
  312.   if (w->skewb.orient != c->skewb.orient) {
  313.     ResetPolyhedrons(w);
  314.     redraw = TRUE;
  315.   } else if (w->skewb.practice != c->skewb.practice) {
  316.     ResetPolyhedrons(w);
  317.     redraw = TRUE;
  318.   }
  319.   if (w->skewb.currentDirection == SKEWB_RESTORE) {
  320.     SetStartPosition(w);
  321.     w->skewb.currentDirection = SKEWB_IGNORE;
  322.   } else if (w->skewb.currentDirection != SKEWB_IGNORE) {
  323.     MovePolyhedrons(w, w->skewb.currentFace, w->skewb.currentPosition,
  324.       w->skewb.currentDirection);
  325.     w->skewb.currentDirection = SKEWB_IGNORE;
  326.   }
  327.   return redraw;
  328. }
  329.  
  330. void QuitSkewb(w, event, args, nArgs)
  331.   SkewbWidget w;
  332.   XEvent *event;
  333.   char *args[];
  334.   int nArgs;
  335. {
  336.   XtCloseDisplay(XtDisplay(w));
  337.   exit(0);
  338. }
  339.  
  340. void SelectSkewb(w, event, args, nArgs)
  341.   SkewbWidget w;
  342.   XEvent *event;
  343.   char *args[];
  344.   int nArgs;
  345. {
  346.   int control, alt;
  347.  
  348.   if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
  349.              &(w->skewb.currentFace), &(w->skewb.currentPosition)) &&
  350.         w->skewb.currentPosition != MAXORIENT) {
  351.     control = (int) (event->xkey.state & ControlMask);
  352.     alt = (int) (event->xkey.state &
  353.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask));
  354.     if (control || alt || w->skewb.practice || !CheckSolved(w))
  355.       DrawTriangle(w, w->skewb.currentFace, w->skewb.currentPosition,
  356.         TRUE);
  357.   } else {
  358.     w->skewb.currentFace = SKEWB_IGNORE;
  359.     w->skewb.currentDirection = SKEWB_IGNORE;
  360.   }
  361. }
  362.  
  363. void ReleaseSkewb(w, event, args, nArgs)
  364.   SkewbWidget w;
  365.   XEvent *event;
  366.   char *args[];
  367.   int nArgs;
  368. {
  369.   int control, alt, face, position, count = -1, direction = 0;
  370.   skewbCallbackStruct cb;
  371.  
  372.   if (w->skewb.currentFace == SKEWB_IGNORE)
  373.     return;
  374.   DrawTriangle(w, w->skewb.currentFace, w->skewb.currentPosition, FALSE);
  375.   control = (int) (event->xkey.state & ControlMask);
  376.   alt = (int) (event->xkey.state &
  377.     (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask));
  378.   if (!control && !alt && !w->skewb.practice && CheckSolved(w))
  379.     MoveNoPolyhedrons(w);
  380.   else if (SelectPolyhedrons(w, event->xbutton.x, event->xbutton.y,
  381.              &face, &position) && position != MAXORIENT &&
  382.              position != w->skewb.currentPosition) {
  383.     if (alt)
  384.       control = 2;
  385.     else
  386.       control = (control) ? 1 : 0;
  387.     if (face == w->skewb.currentFace)
  388.       count = CheckMoveDir(w->skewb.currentPosition, position, &direction);
  389.     if (count == 1) {
  390.       MoveSkewb(w, face, w->skewb.currentPosition, direction, control);
  391.       if (!control && CheckSolved(w)) {
  392.         cb.reason = SKEWB_SOLVED;
  393.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  394.       }
  395.     } else if (count == 0)
  396.       MoveNoPolyhedrons(w);
  397.   }
  398.   w->skewb.currentFace = SKEWB_IGNORE;
  399.   w->skewb.currentDirection = SKEWB_IGNORE;
  400. }
  401.  
  402. void PracticeSkewb(w, event, args, nArgs)
  403.   SkewbWidget w;
  404.   XEvent *event;
  405.   char *args[];
  406.   int nArgs;
  407. {
  408.   PracticePolyhedrons(w);
  409. }
  410.  
  411. void PracticeSkewbMaybe(w, event, args, nArgs)
  412.   SkewbWidget w;
  413.   XEvent *event;
  414.   char *args[];
  415.   int nArgs;
  416. {
  417.   if (!w->skewb.started)
  418.     PracticePolyhedrons(w);
  419. }
  420.  
  421. void RandomizeSkewb(w, event, args, nArgs)
  422.   SkewbWidget w;
  423.   XEvent *event;
  424.   char *args[];
  425.   int nArgs;
  426. {
  427.   RandomizePolyhedrons(w);
  428. }
  429.  
  430. void RandomizeSkewbMaybe(w, event, args, nArgs)
  431.   SkewbWidget w;
  432.   XEvent *event;
  433.   char *args[];
  434.   int nArgs;
  435. {
  436.   if (!w->skewb.started)
  437.     RandomizePolyhedrons(w);
  438. }
  439.  
  440. void GetSkewb(w, event, args, nArgs)
  441.   SkewbWidget w;
  442.   XEvent *event;
  443.   char *args[];
  444.   int nArgs;
  445. {
  446.   FILE *fp;
  447.   char c;
  448.   int orient, practice, moves;
  449.   skewbCallbackStruct cb;
  450.  
  451.   if ((fp = fopen(DATAFILE, "r")) == NULL)
  452.     (void) printf("Can not read %s for get.\n", DATAFILE);
  453.   else {
  454.     FlushMoves(w);
  455.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  456.     (void) fscanf(fp, "%d", &orient);
  457.     if (w->skewb.orient != (Boolean) orient) {
  458.       cb.reason = SKEWB_ORIENT;
  459.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  460.     }
  461.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  462.     (void) fscanf(fp, "%d", &practice);
  463.     if (w->skewb.practice != (Boolean) practice) {
  464.       cb.reason = SKEWB_PRACTICE;
  465.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  466.     }
  467.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  468.     (void) fscanf(fp, "%d", &moves);
  469.     ScanStartPosition(fp, w);
  470.     cb.reason = SKEWB_RESTORE;
  471.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  472.     ScanMoves(fp, w, moves);
  473.     (void) fclose(fp);
  474.     (void) printf("%s: orient %d, practice %d, moves %d.\n",
  475.       DATAFILE, orient, practice, moves);
  476.   }
  477. }
  478.  
  479. void WriteSkewb(w, event, args, nArgs)
  480.   SkewbWidget w;
  481.   XEvent *event;
  482.   char *args[];
  483.   int nArgs;
  484. {
  485.   FILE *fp;
  486.  
  487.   if ((fp = fopen(DATAFILE, "w")) == NULL)
  488.     (void) printf("Can not write to %s.\n", DATAFILE);
  489.   else {
  490.     (void) fprintf(fp, "orient%c %d\n", SYMBOL, (w->skewb.orient) ? 1 : 0);
  491.     (void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->skewb.practice) ? 1 : 0);
  492.     (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
  493.     PrintStartPosition(fp, w);
  494.     PrintMoves(fp);
  495.     (void) fclose(fp);
  496.     (void) printf("Saved to %s.\n", DATAFILE);
  497.   }
  498. }
  499.  
  500. void UndoSkewb(w, event, args, nArgs)
  501.   SkewbWidget w;
  502.   XEvent *event;
  503.   char *args[];
  504.   int nArgs;
  505. {
  506.   if (MadeMoves()) {
  507.     int face, position, direction, control;
  508.  
  509.     GetMove(&face, &position, &direction, &control);
  510.     if (direction < 2 * MAXORIENT)
  511.       direction = (direction < MAXORIENT) ? (direction + MAXORIENT / 2) %
  512.         MAXORIENT : 3 * MAXORIENT - direction;
  513.     else
  514.       direction = 5 * MAXORIENT - direction;
  515.     if (control == 2)
  516.       MoveAltCb(w, face, position, direction);
  517.     else if (control)
  518.       MoveControlCb(w, face, position, direction);
  519.     else {
  520.       skewbCallbackStruct cb;
  521.  
  522.       if (direction >= 2 * MAXORIENT) {
  523.         SkewbLocPos newpos;
  524.  
  525.         newpos = orthToDiag[face][position][direction % MAXORIENT];
  526.         face = newpos.face;
  527.         position = newpos.position;
  528.         direction = newpos.direction;
  529.       }
  530.       MovePolyhedrons(w, face, position, direction);
  531.       cb.reason = SKEWB_UNDO;
  532.       cb.face = face;
  533.       cb.position = position;
  534.       cb.direction = direction;
  535.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  536.     }
  537.   }
  538. }
  539.  
  540. void SolveSkewb(w, event, args, nArgs)
  541.   SkewbWidget w;
  542.   XEvent *event;
  543.   char *args[];
  544.   int nArgs;
  545. {
  546.   /* SolvePolyhedrons(w); */ /* Sorry, unimplemented */
  547. }
  548.  
  549. void OrientizeSkewb(w, event, args, nArgs)
  550.   SkewbWidget w;
  551.   XEvent *event;
  552.   char *args[];
  553.   int nArgs;
  554. {
  555.   skewbCallbackStruct cb;
  556.  
  557.   cb.reason = SKEWB_ORIENT;
  558.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  559. }
  560.  
  561. void MoveSkewbCcw(w, event, args, nArgs)
  562.   SkewbWidget w;
  563.   XEvent *event;
  564.   char *args[];
  565.   int nArgs;
  566. {
  567.   MoveSkewbInput(w, event->xbutton.x, event->xbutton.y, CCW,
  568.     (int) (event->xbutton.state & ControlMask), FALSE);
  569. }
  570.  
  571. void MoveSkewbCw(w, event, args, nArgs)
  572.   SkewbWidget w;
  573.   XEvent *event;
  574.   char *args[];
  575.   int nArgs;
  576. {
  577.   MoveSkewbInput(w, event->xbutton.x, event->xbutton.y, CW,
  578.     (int) (event->xkey.state & ControlMask), FALSE);
  579. }
  580.  
  581. void MoveSkewbInput(w, x, y, direction, control, alt)
  582.   SkewbWidget w;
  583.   int x, y, direction, control, alt;
  584. {
  585.   int face, position;
  586.  
  587.   if (!w->skewb.practice && !control && !alt && CheckSolved(w)) {
  588.     MoveNoPolyhedrons(w);
  589.     return;
  590.   }
  591.   if (!PositionPolyhedrons(w, x, y, &face, &position, &direction))
  592.     return;
  593.   if (alt)
  594.     control = 2;
  595.   else
  596.     control = (control) ? 1 : 0;
  597.   if (position == MAXORIENT)
  598.     return;
  599.   MoveSkewb(w, face, position, direction, control);
  600.   if (!control && CheckSolved(w)) {
  601.     skewbCallbackStruct cb;
  602.  
  603.     cb.reason = SKEWB_SOLVED;
  604.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  605.   }
  606. }
  607.  
  608. void MoveSkewb(w, face, position, direction, control)
  609.   SkewbWidget w;
  610.   int face, position, direction, control;
  611. {
  612.   if (control == 2)
  613.     MoveAltCb(w, face, position, direction);
  614.   else if (control)
  615.     MoveControlCb(w, face, position, direction);
  616.   else {
  617.     SkewbLocPos newpos;
  618.     skewbCallbackStruct cb;
  619.  
  620.     newpos.face = face;
  621.     newpos.position = position;
  622.     newpos.direction = direction;
  623.     if (direction >= 2 * MAXORIENT)
  624.       newpos = orthToDiag[face][position][direction % MAXORIENT];
  625.     MovePolyhedrons(w, newpos.face, newpos.position, newpos.direction);
  626.     cb.reason = SKEWB_MOVED;
  627.     cb.face = newpos.face;
  628.     cb.position = newpos.position;
  629.     cb.direction = newpos.direction;
  630.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  631.   }
  632.   PutMove(face, position, direction, control);
  633. }
  634.  
  635. static void GetColor(w, face, init)
  636.   SkewbWidget w;
  637.   int face, init;
  638. {
  639.   XGCValues values;
  640.   XtGCMask valueMask;
  641.   XColor colorCell, rgb;
  642.  
  643.   valueMask = GCForeground | GCBackground;
  644.   values.background = w->core.background_pixel;
  645.   if (w->skewb.depth > 1 && !w->skewb.mono) {
  646.     if (XAllocNamedColor(XtDisplay(w),
  647.         DefaultColormap(XtDisplay(w), XtWindow(w)),
  648.         w->skewb.faceName[face], &colorCell, &rgb)) {
  649.       values.foreground = w->skewb.faceColor[face] = colorCell.pixel;
  650.       if (!init)
  651.         XtReleaseGC((Widget) w, w->skewb.faceGC[face]);
  652.       w->skewb.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
  653.       return;
  654.     } else {
  655.       char buf[121];
  656.  
  657.       (void) sprintf(buf, "Color name \"%s\" is not defined",
  658.                w->skewb.faceName[face]);
  659.       XtWarning(buf);
  660.     }
  661.   }
  662.   values.foreground = w->skewb.foreground;
  663.   if (!init)
  664.     XtReleaseGC((Widget) w, w->skewb.faceGC[face]);
  665.   w->skewb.faceGC[face] = XtGetGC((Widget) w, valueMask, &values);
  666. }
  667.  
  668. static void MoveControlCb(w, face, position, direction)
  669.   SkewbWidget w;
  670.   int face, position, direction;
  671. {
  672.   skewbCallbackStruct cb;
  673.   int newFace, rotate;
  674.  
  675.   if (direction >= 2 * MAXORIENT) {
  676.     SkewbLocPos newpos;
  677.  
  678.     newpos = orthToDiag[face][position][direction % MAXORIENT];
  679.     face = newpos.face;
  680.     position = newpos.position;
  681.     direction = newpos.direction;
  682.   }
  683.   MovePolyhedrons(w, face, position, direction);
  684.   cb.reason = SKEWB_CONTROL;
  685.   cb.face = face;
  686.   cb.position = position;
  687.   cb.direction = direction;
  688.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  689.   newFace = minToMaj[face][position].face;
  690.   rotate = minToMaj[face][position].rotation % MAXORIENT;
  691.   direction = (rotate + direction) % MAXORIENT;
  692.   position = (position + rotate + 2) % MAXORIENT;
  693.   MovePolyhedrons(w, newFace, position, direction);
  694.   cb.face = newFace;
  695.   cb.position = position;
  696.   cb.direction = direction;
  697.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  698. }
  699.  
  700. static void MoveAltCb(w, face, position, direction)
  701.   SkewbWidget w;
  702.   int face, position, direction;
  703. {
  704.   skewbCallbackStruct cb;
  705.  
  706.   MovePolyhedrons(w, face, position, direction);
  707.   cb.reason = SKEWB_CONTROL;
  708.   cb.face = face;
  709.   cb.position = position;
  710.   cb.direction = direction;
  711.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  712. }
  713.  
  714. static void ResetPolyhedrons(w)
  715.   SkewbWidget w;
  716. {
  717.   int face, position;
  718.  
  719.   for (face = 0; face < MAXFACES; face++)
  720.     for (position = 0; position < MAXCUBES; position++) {
  721.       w->skewb.cubeLoc[face][position].face = face;
  722.       w->skewb.cubeLoc[face][position].rotation = STRT - MAXORIENT;
  723.     }
  724.   FlushMoves(w);
  725.   w->skewb.started = FALSE;
  726. }
  727.  
  728. static int SelectPolyhedrons(w, x, y, face, position)
  729.   SkewbWidget w;
  730.   int x, y;
  731.   int *face;
  732.   int *position;
  733. {
  734.   if (w->skewb.dim == 2)
  735.     return SelectPolyhedrons2D((Skewb2DWidget) w, x, y,
  736.       face, position);
  737.   else if (w->skewb.dim == 3)
  738.     return SelectPolyhedrons3D((Skewb3DWidget) w, x, y,
  739.       face, position);
  740.   return FALSE;
  741. }
  742.  
  743. static int NarrowSelection(w, face, position, direction)
  744.   SkewbWidget w;
  745.   int *face;
  746.   int *position;
  747.   int *direction;
  748. {
  749.   if (w->skewb.dim == 2)
  750.     return NarrowSelection2D((Skewb2DWidget) w, face, position, direction);
  751.   else if (w->skewb.dim == 3)
  752.     return NarrowSelection3D((Skewb3DWidget) w, face, position, direction);
  753.   return FALSE;
  754. }
  755.  
  756. static int PositionPolyhedrons(w, x, y, face, position, direction)
  757.   SkewbWidget w;
  758.   int x, y;
  759.   int *face;
  760.   int *position;
  761.   int *direction;
  762. {
  763.   if (!SelectPolyhedrons(w, x, y, face, position))
  764.     return FALSE;
  765.   return NarrowSelection(w, face, position, direction);
  766. }
  767.  
  768. static void MoveNoPolyhedrons(w)
  769.   SkewbWidget w;
  770. {
  771.   skewbCallbackStruct cb;
  772.  
  773.   cb.reason = SKEWB_ILLEGAL;
  774.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  775. }
  776.  
  777. static void PracticePolyhedrons(w)
  778.   SkewbWidget w;
  779. {
  780.   skewbCallbackStruct cb;
  781.  
  782.   cb.reason = SKEWB_PRACTICE;
  783.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  784. }
  785.  
  786. static void RandomizePolyhedrons(w)
  787.   SkewbWidget w;
  788. {
  789.   skewbCallbackStruct cb;
  790.   int face, position, direction;
  791.   int big = MAXCUBES * 3 + NRAND(2);
  792.  
  793.   if (w->skewb.practice)
  794.     PracticePolyhedrons(w);
  795.   cb.reason = SKEWB_RESET;
  796.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  797.  
  798. #ifdef DEBUG
  799.   big = 3;
  800. #endif
  801.  
  802.   while (big--) {
  803.     face = NRAND(MAXFACES);
  804.     position = NRAND(MAXORIENT);
  805.     direction = ((NRAND(2)) ? position + 1 : position + 3) % MAXORIENT;
  806.     MoveSkewb(w, face, position, direction, FALSE);
  807.   }
  808.   FlushMoves(w);
  809.   cb.reason = SKEWB_RANDOMIZE;
  810.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  811.   if (CheckSolved(w)) {
  812.     cb.reason = SKEWB_SOLVED;
  813.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  814.   }
  815. }
  816.  
  817. static void MovePolyhedrons(w, face, position, direction)
  818.   SkewbWidget w;
  819.   int face, position, direction;
  820. {
  821.   int newFace, newDirection, newCorner, k, size, rotate;
  822.  
  823.   if (direction < 2 * MAXORIENT) {
  824.     /* position as MAXORIENT is ambiguous */
  825.     for (size = MINOR; size <= MAJOR; size++) {
  826.       ReadDiagonal((SkewbWidget) w, face, position, 0, size);
  827.       for (k = 1; k <= MAXROTATE; k++) {
  828.         newFace = slideNextRow[face][position][direction / 2].face;
  829.         rotate = slideNextRow[face][position][direction / 2].rotation %
  830.           MAXORIENT;
  831.         newDirection = (rotate + direction) %  MAXORIENT;
  832.         newCorner = (rotate + position) %  MAXORIENT;
  833.         if (k != MAXROTATE)
  834.           ReadDiagonal((SkewbWidget) w, newFace, newCorner, k, size);
  835.         RotateDiagonal((SkewbWidget) w, rotate, k - 1, size);
  836.         WriteDiagonal(w, newFace, newCorner, k - 1, size);
  837.         face = newFace;
  838.         position = newCorner;
  839.         direction = newDirection;
  840.       }
  841.       if (size == MINOR) {
  842.         newFace = minToMaj[face][position].face;
  843.         rotate = minToMaj[face][position].rotation % MAXORIENT;
  844.         direction = (rotate + direction) % MAXORIENT;
  845.         position = (position + rotate + 2) % MAXORIENT;
  846.         face = newFace;
  847.       }
  848.     }
  849.   } else {
  850.     RotateFace(w, faceToRotate[face][direction % MAXORIENT], CW);
  851.     RotateFace(w, faceToRotate[face][(direction + 2) % MAXORIENT], CCW);
  852.     ReadFace((SkewbWidget) w, face, 0);
  853.     for (k = 1; k <= MAXORIENT; k++) {
  854.       newFace = slideNextFace[face][direction % MAXORIENT].face;
  855.       rotate = slideNextFace[face][direction % MAXORIENT].rotation;
  856.       newDirection = (rotate + direction) % MAXORIENT;
  857.       if (k != MAXORIENT)
  858.         ReadFace((SkewbWidget) w, newFace, k);
  859.       WriteFace(w, newFace, rotate, k - 1);
  860.       face = newFace;
  861.       direction = newDirection;
  862.     }
  863.   }
  864. }
  865.  
  866. static void ReadDiagonal(w, face, corner, orient, size)
  867.   SkewbWidget w;
  868.   int face, corner, orient, size;
  869. {
  870.   int g;
  871.  
  872.   if (size == MINOR)
  873.     w->skewb.minorLoc[orient] = w->skewb.cubeLoc[face][corner];
  874.   else /* size == MAJOR */
  875.   {
  876.     for (g = 1; g < MAXORIENT; g++)
  877.       w->skewb.majorLoc[orient][g - 1] =
  878.         w->skewb.cubeLoc[face][(corner + g) % MAXORIENT];
  879.     w->skewb.majorLoc[orient][MAXORIENT - 1] =
  880.       w->skewb.cubeLoc[face][MAXORIENT];
  881.   }
  882. }
  883.  
  884. static void RotateDiagonal(w, rotate, orient, size)
  885.   SkewbWidget w;
  886.   int rotate, orient, size;
  887. {
  888.   int g;
  889.  
  890.   if (size == MINOR)
  891.     w->skewb.minorLoc[orient].rotation =
  892.       (w->skewb.minorLoc[orient].rotation + rotate) % MAXORIENT;
  893.   else /* size == MAJOR */
  894.     for (g = 0; g < MAXORIENT; g++)
  895.       w->skewb.majorLoc[orient][g].rotation =
  896.         (w->skewb.majorLoc[orient][g].rotation + rotate) % MAXORIENT;
  897. }
  898.  
  899. static void WriteDiagonal(w, face, corner, orient, size)
  900.   SkewbWidget w;
  901.   int face, corner, orient, size;
  902. {
  903.   int g, h;
  904.  
  905.   if (size == MINOR) {
  906.     w->skewb.cubeLoc[face][corner] = w->skewb.minorLoc[orient];
  907.     DrawTriangle(w, face, corner, FALSE);
  908.   } else /* size == MAJOR */ {
  909.     w->skewb.cubeLoc[face][MAXORIENT] =
  910.       w->skewb.majorLoc[orient][MAXORIENT - 1];
  911.     DrawDiamond(w, face);
  912.     for (g = 1; g < MAXORIENT; g++) {
  913.       h = (corner + g) % MAXORIENT;
  914.       w->skewb.cubeLoc[face][h] = w->skewb.majorLoc[orient][g - 1];
  915.       DrawTriangle(w, face, h, FALSE);
  916.     }
  917.   }
  918. }
  919.  
  920. static void ReadFace(w, face, h)
  921.   SkewbWidget w;
  922.   int face, h;
  923. {
  924.   int position;
  925.  
  926.   for (position = 0; position < MAXCUBES; position++)
  927.     w->skewb.rowLoc[h][position] = w->skewb.cubeLoc[face][position];
  928. }
  929.  
  930. static void WriteFace(w, face, rotate, h)
  931.   SkewbWidget w;
  932.   int face, rotate, h;
  933. {
  934.   int corner, newCorner;
  935.  
  936.   for (corner = 0; corner < MAXORIENT; corner++) {
  937.     newCorner = (corner + rotate) % MAXORIENT;
  938.     w->skewb.cubeLoc[face][newCorner] = w->skewb.rowLoc[h][corner];
  939.     w->skewb.cubeLoc[face][newCorner].rotation =
  940.       (w->skewb.cubeLoc[face][newCorner].rotation + rotate) % MAXORIENT;
  941.     DrawTriangle(w, face, (corner + rotate) % MAXORIENT, FALSE);
  942.   }
  943.   w->skewb.cubeLoc[face][MAXORIENT] = w->skewb.rowLoc[h][MAXORIENT];
  944.   w->skewb.cubeLoc[face][MAXORIENT].rotation =
  945.     (w->skewb.cubeLoc[face][MAXORIENT].rotation + rotate) % MAXORIENT;
  946.   DrawDiamond(w, face);
  947. }
  948.  
  949. static void RotateFace(w, face, direction)
  950.   SkewbWidget w;
  951.   int face, direction;
  952. {
  953.   int corner;
  954.  
  955.   /* Read Face */
  956.   for (corner = 0; corner < MAXORIENT; corner++)
  957.     w->skewb.faceLoc[corner] = w->skewb.cubeLoc[face][corner];
  958.   /* Write Face */
  959.   for (corner = 0; corner < MAXORIENT; corner++) {
  960.     w->skewb.cubeLoc[face][corner] = (direction == CW) ?
  961.       w->skewb.faceLoc[(corner + MAXORIENT - 1) % MAXORIENT]:
  962.       w->skewb.faceLoc[(corner + 1) % MAXORIENT];
  963.     w->skewb.cubeLoc[face][corner].rotation =
  964.       (w->skewb.cubeLoc[face][corner].rotation + direction) % MAXORIENT;
  965.     DrawTriangle(w, face, corner, FALSE);
  966.   }
  967.   w->skewb.cubeLoc[face][MAXORIENT].rotation =
  968.     (w->skewb.cubeLoc[face][MAXORIENT].rotation + direction) % MAXORIENT;
  969.   DrawDiamond(w, face);
  970. }
  971.  
  972. void DrawAllPolyhedrons(w)
  973.   SkewbWidget w;
  974. {
  975.   int face, position;
  976.  
  977.   for (face = 0; face < MAXFACES; face++) {
  978.     DrawDiamond(w, face);
  979.     for (position = 0; position < MAXORIENT; position++)
  980.       DrawTriangle(w, face, position, FALSE);
  981.   }
  982. }
  983.  
  984. static void DrawDiamond(w, face)
  985.   SkewbWidget w;
  986.   int face;
  987. {
  988.   if (w->skewb.dim == 2)
  989.     DrawDiamond2D((Skewb2DWidget) w, face);
  990.   else if (w->skewb.dim == 3)
  991.     DrawDiamond3D((Skewb3DWidget) w, face);
  992. }
  993.  
  994. static void DrawTriangle(w, face, position, offset)
  995.   SkewbWidget w;
  996.   int face, position, offset;
  997. {
  998.   if (w->skewb.dim == 2)
  999.     DrawTriangle2D((Skewb2DWidget) w, face, position, offset);
  1000.   else if (w->skewb.dim == 3)
  1001.     DrawTriangle3D((Skewb3DWidget) w, face, position, offset);
  1002. }
  1003.  
  1004. Boolean CheckSolved(w)
  1005.   SkewbWidget w;
  1006. {
  1007.   int face, position;
  1008.   SkewbLoc test;
  1009.  
  1010.   for (face = 0; face < MAXFACES; face++)
  1011.     for (position = 0; position < MAXCUBES; position++) {
  1012.       if (!position) {
  1013.         test.face = w->skewb.cubeLoc[face][position].face;
  1014.         test.rotation = w->skewb.cubeLoc[face][position].rotation;
  1015.       } else if (test.face != /*face*/
  1016.                w->skewb.cubeLoc[face][position].face ||
  1017.                (w->skewb.orient && test.rotation != /*STRT - MAXORIENT*/
  1018.                 w->skewb.cubeLoc[face][position].rotation))
  1019.           return FALSE;
  1020.     }
  1021.   return TRUE;
  1022. }
  1023.  
  1024. static int CheckMoveDir(position1, position2, direction)
  1025.   int position1, position2, *direction;
  1026. {
  1027.   if (!((position1 - position2 + MAXORIENT) % 2))
  1028.     return FALSE;
  1029.   switch (position1) {
  1030.     case 0:
  1031.       *direction = (position2 == 1) ? 2 : 3;
  1032.       break;
  1033.     case 1:
  1034.       *direction = (position2 == 2) ? 3 : 0;
  1035.       break;
  1036.     case 2:
  1037.       *direction = (position2 == 3) ? 0 : 1;
  1038.       break;
  1039.     case 3:
  1040.       *direction = (position2 == 0) ? 1 : 2;
  1041.       break;
  1042.     default:
  1043.       return FALSE;
  1044.   }
  1045.   *direction += 2 * MAXORIENT;
  1046.   return TRUE;
  1047. }
  1048.  
  1049. #ifdef DEBUG
  1050.  
  1051. void PrintCube(w)
  1052.   SkewbWidget w;
  1053. {
  1054.   int face, position;
  1055.  
  1056.   for (face = 0; face < MAXFACES; face++) {
  1057.     for (position = 0; position < MAXCUBES; position++)
  1058.       (void) printf("%d %d  ", w->skewb.cubeLoc[face][position].face,
  1059.                w->skewb.cubeLoc[face][position].rotation);
  1060.     (void) printf("\n");
  1061.   }
  1062.   (void) printf("\n");
  1063. }
  1064.  
  1065. #endif
  1066.